package com.douma._2022;

import java.util.Scanner;
import java.util.TreeSet;

/**
 * 抖码算法，让算法学习变的简单有趣
 *
 * @作者 : 老汤
 */
public class 服务器广播 {

    private static TreeSet<Integer>[] graph;

    // 用于防止一个节点被重复访问
    private static boolean[] visited;

    private static int ccCount = 0;

    /*
    思路，这道题目本质上是求图有几个联通分量
    有几个联通分量，那么初始就需要给几台服务器广播，才可以使每个服务器都收到广播
     */
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // 1. 构建邻接矩阵
        // 解析第一行，拿到 n
        String[] firstLine = sc.nextLine().split(" ");
        int n = firstLine.length;

        // 构建邻接矩阵
        graph = new TreeSet[n];
        for (int i = 0; i < n; i++) {
            graph[i] = new TreeSet<>();
        }

        // 根据第一行初始化顶点 0 的邻居顶点
        for (int i = 0; i < n; i++) {
            if (i > 0 && firstLine[i].equals("1")) {
                graph[0].add(i);
                graph[i].add(0);
            }
        }

        // 初始化其他顶点的邻居顶点
        for (int i = 1; i < n; i++) {
            String[] nums = sc.nextLine().split(" ");
            for (int j = 0; j < n; j++) {
                if (i != j && nums[j].equals("1")) {
                    graph[i].add(j);
                    graph[j].add(i);
                }
            }
        }

        // 2. 计算连通分量
        visited = new boolean[n];
        // 遍历图中每个顶点
        for (int v = 0; v < n; v++) {
            // 先判断，没有遍历的顶点才能进行深度优先遍历
            if (!visited[v]) {
                ccCount++;
                dfs(v);
            }
        }

        System.out.println(ccCount);

        sc.close();
    }

    private static void dfs(int v) {
        visited[v] = true;
        for (int w : graph[v]) {
            if (!visited[w]) {
                dfs(w);
            }
        }
    }

}
